package com.jhy.guavacase.io;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.io.CharSink;
import com.google.common.io.FileWriteMode;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jhy
 * @ClassName FilesCase.java
 * @Description Guava中关于IO文件的操作
 * @createTime 2022年02月23日 14:52:00
 */
public class FilesCase {

    //源文件位置
    private final String SOURCE_FILE= "E:\\java项目\\Guava学习\\guava-case\\guava-case\\src\\main\\resources\\io\\sourceFile.txt";
    //目标文件位置
    private final String TARGET_FILE = "E:\\java项目\\Guava学习\\guava-case\\guava-case\\src\\main\\resources\\io\\targetFile.txt";


    //1.文件复制
    @Test
    public void testCopy() throws IOException {
        File sourceFile = new File(SOURCE_FILE);
        File targetFile = new File(TARGET_FILE);
        Files.copy(sourceFile,targetFile);
        Assertions.assertEquals(targetFile.exists(),true);
    }

    //2.文件移动
    @Test
    public void testMove() throws IOException {
        File sourceFile = new File(SOURCE_FILE);
        File targetFile = new File(TARGET_FILE);
        Files.move(sourceFile,targetFile);
        Assertions.assertEquals(sourceFile.exists(),false);
        Assertions.assertEquals(targetFile.exists(),true);
        //恢复源文件
        Files.move(targetFile,sourceFile);
    }

    //3.读取文件内容为字符串
    @Test
    public void testReadLines() throws IOException {
        final String EXPECTED_STRINGS = "认真阅读源码撒！！！\n" +
                "Guava";
        //其中又用到了Guava中的Charsets，维护了各种编码，方便调用
        List<String> stringList = Files.readLines(new File(SOURCE_FILE), Charsets.UTF_8);
        //Files.readLines(new File(SOURCE_FILE),Charset.forName("UTF-8"));
        Assertions.assertEquals(stringList.size(),2);
        String result = Joiner.on("\n").join(stringList);
        Assertions.assertTrue(result.equals(EXPECTED_STRINGS));
    }

    //4.行处理器的使用
    @Test
    public void testLineProcessor() throws IOException {

        LineProcessor<List<Integer>> lineProcessor = new LineProcessor<List<Integer>>() {
            //定义一个整数列表，存储每一行的长度
            List<Integer> lenList = new ArrayList<>();

            //处理每一行的方式
            @Override
            public boolean processLine(String line) throws IOException {
                lenList.add(line.length());
                return true; //总是返回true，表示处理所有行
            }

            //返回处理所有行之后的结果
            @Override
            public List<Integer> getResult() {
                return lenList;
            }
        };

        List<Integer> res = Files.asCharSource(new File(SOURCE_FILE), Charsets.UTF_8).readLines(lineProcessor);
        System.out.println(res);
    }

    //5.hash算法的调用
    @Test
    public void testHash() throws IOException {
        File file = new File(SOURCE_FILE);
        HashCode hash = Files.asByteSource(file).hash(Hashing.sha256());
        System.out.println("哈希值：" + hash.toString());

    }

    //6.文件写出
    @Test
    public void testFileWriter() throws IOException {
        File targetFile = new File(TARGET_FILE);
        targetFile.deleteOnExit();
        String content = "尝试文件写出";
        Files.asCharSink(targetFile,Charsets.UTF_8).write(content);
        //写完读一下做验证
        String res = Files.asCharSource(targetFile, Charsets.UTF_8).read();
        Assertions.assertEquals(content,res);
    }

    //7.使用append的方式写文件
    @Test
    public void testFileAppendWrite() throws IOException {
        File targetFile = new File(TARGET_FILE);
        targetFile.deleteOnExit();
        //创建append方式的输出流
        CharSink charSink = Files.asCharSink(targetFile, Charsets.UTF_8, FileWriteMode.APPEND);
        charSink.write("append1");
        //验证
        String res = Files.asCharSource(targetFile, Charsets.UTF_8).read();
        Assertions.assertEquals(res,"append1");
        //append
        charSink.write("append2");
        res = Files.asCharSource(targetFile, Charsets.UTF_8).read();
        Assertions.assertEquals(res,"append1append2");
    }

    //8.使用touch创建一个空白文件
    @Test
    public void testTouchFile() throws IOException {
        File targetFile = new File(TARGET_FILE);
        targetFile.deleteOnExit();
        Files.touch(targetFile);
        Assertions.assertEquals(targetFile.exists(),true);
    }

    //9.自己实现递归文件夹
    @Test
    public void testRecursiveFileSelf(){
        File root = new File("E:\\java项目\\Guava学习\\guava-case\\guava-case\\src\\main");
        List<File> fileList = new ArrayList<>();
        recursiveFileSelf(root,fileList);
        fileList.forEach(System.out::println);
    }

    private void recursiveFileSelf(File root, List<File> fileList){
        /*//1.文件夹和文件均要
        //隐藏文件夹不处理
        if(root.isHidden()) return;
        //不论文件还是文件夹，全部处理
        fileList.add(root);
        if(root.isDirectory()){ //文件夹需要递归处理
            File[] files = root.listFiles();
            for(File file: files){
                recursiveFileSelf(file,fileList);
            }
        }*/

        //2.只处理文件
        if(root.isHidden()) return;
        if(root.isFile()){ //文件直接添加
            fileList.add(root);
        }else { //文件夹，递归
            File[] files = root.listFiles();
            for(File file : files){
                recursiveFileSelf(file,fileList);
            }
        }
    }

    //10.自己递归删除文件夹
    @Test
    public void testRecursiveDeleteFile(){
        File root = new File("E:\\deleteTest");
        //直接删除有子文件的目录会失败
        //boolean delete = root.delete();
        //Assertions.assertEquals(delete,false);
        recursiveDeleteFile(root);
    }

    private void recursiveDeleteFile(File root){

        //不存在，直接返回
        if(!root.exists()) return;

        if(root.isFile()){
            root.delete();
            System.out.println("删除文件：" + root.getName());
        }else { //文件夹需要递归
            File[] files = root.listFiles();
            for(File file : files){
                recursiveDeleteFile(file);
            }
            //跳出递归，删除当前文件夹
            root.delete();
            System.out.println("删除了文件夹：" + root.getName());
        }
    }

    //11.使用Guava实现文件递归-->深度有优先并且前序遍历
    @Test
    public void testDepthFirstPreOrder(){
        File root = new File("E:\\java项目\\Guava学习\\guava-case\\guava-case\\src\\main");
        //文件和文件夹
        Iterable<File> files = Files.fileTraverser().depthFirstPreOrder(root);
        files.forEach(System.out::println);
    }


    //单元测试不要依赖和修改外部数据等共享资源，做到测试前后共享资源数据一致
    //注意：在junit5中@After和@Before分别被@AfterEach和@BeforeEach替代
    @AfterEach
    public void tearDown(){
        File targetFile = new File(TARGET_FILE);
        if(targetFile.exists()){
            targetFile.delete();
        }
    }

}
